package cn.s1995.sloth.app.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.s1995.sloth.bizs.constant.BizCst;
import cn.s1995.sloth.common.core.constant.enums.hint.Hint;
import cn.s1995.sloth.bizs.entity.*;
import cn.s1995.sloth.bizs.enums.NotifyTemplateEnum;
import cn.s1995.sloth.bizs.event.ConfirmOrderEvent;
import cn.s1995.sloth.bizs.exception.BizException;
import cn.s1995.sloth.bizs.oo.dto.ShopCartDTO;
import cn.s1995.sloth.bizs.oo.dto.ShopCartItemDTO;
import cn.s1995.sloth.bizs.oo.dto.ShopCartItemDiscountDTO;
import cn.s1995.sloth.bizs.oo.dto.ShopCartOrderDTO;
import cn.s1995.sloth.bizs.oo.req.ChangeCartREQ;
import cn.s1995.sloth.bizs.oo.req.OrderREQ;
import cn.s1995.sloth.bizs.oo.req.OrderRefundREQ;
import cn.s1995.sloth.bizs.oo.req.SubmitOrderREQ;
import cn.s1995.sloth.bizs.oo.vo.OrderItemVO;
import cn.s1995.sloth.bizs.oo.vo.OrderVO;
import cn.s1995.sloth.bizs.oo.vo.ShopCartOrderMergerVO;
import cn.s1995.sloth.bizs.service.*;
import cn.s1995.sloth.bizs.service.common.CacheService;
import cn.s1995.sloth.common.core.util.R;
import cn.s1995.sloth.common.security.util.SecurityUtils;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * CommonController
 *
 * @author Lex
 * @description 我的
 * @date 2023/12/23 17:14
 */
@RestController
@RequestMapping("/m/order")
@RequiredArgsConstructor
@Tag(description = "OrderController", name = "APP-订单")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class ApiOrderController {

    private final OrderService orderService;
    private final OrderItemService orderItemService;
    private final SkuService skuService;
    private final ProdService productService;
    private final UserAddressService userAddressService;
    private final CartService cartService;
    private final ApplicationContext applicationContext;
    private final OrderRefundService orderRefundService;
    private final MessageService messageService;
    private final CacheService cacheService;
    private final ProdService prodService;

    /**
     * 生成订单
     */
    @ApiOperationSupport(order = 10)
    @PostMapping("/confirm")
    @Operation(summary = "结算-生成订单信息", description = "传入下单所需要的参数进行下单")
    public R<ShopCartOrderMergerVO> confirm(@Valid @RequestBody OrderREQ req) {
        Long userId = SecurityUtils.getUser().getId();

        // 地址为null处理
        if (Objects.isNull(req.getAddrId())) {
            req.setAddrId(0L);
        }
        // 订单的地址信息
        UserAddress userAddr = userAddressService.getUserAddrByUserId(req.getAddrId(), userId);
        // if (Objects.isNull(userAddr)) {
        //     throw new BizException(Hint.APP_PLEASE_SELECT_THE_RECEIVING_ADDRESS);
        // }

        // 组装获取用户提交的购物车商品项
        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItemsByOrderItems(req.getCartIds(), req.getOrderItem(), userId);

        if (CollectionUtil.isEmpty(shopCartItems)) {
            throw new BizException(Hint.APP_PLEASE_CHOOSE_YOUR_NEED_TO_ADD_TO_THE_SHOPPING_CART);
        }

        // 根据店铺组装购车中的商品信息，返回每个店铺中的购物车商品信息
        List<ShopCartDTO> shopCarts = cartService.getShopCarts(shopCartItems);

        // 将要返回给前端的完整的订单信息
        ShopCartOrderMergerVO shopCartOrderMergerDto = new ShopCartOrderMergerVO();

        shopCartOrderMergerDto.setUserAddr(userAddr);

        // 所有店铺的订单信息
        List<ShopCartOrderDTO> shopCartOrders = new ArrayList<>();

        BigDecimal actualTotal = BigDecimal.ZERO;
        BigDecimal freightTotal = BigDecimal.ZERO;
        BigDecimal total = BigDecimal.ZERO;
        int totalCount = 0;
        BigDecimal orderReduce = BigDecimal.ZERO;
        for (ShopCartDTO shopCart : shopCarts) {

            // 每个店铺的订单信息
            ShopCartOrderDTO shopCartOrder = new ShopCartOrderDTO();
            shopCartOrder.setShopId(shopCart.getShopId());
            shopCartOrder.setShopName(shopCart.getShopName());
            shopCartOrder.setShopAvatar(shopCart.getShopAvatar());

            List<ShopCartItemDiscountDTO> shopCartItemDiscounts = shopCart.getShopCartItemDiscounts();

            // 店铺中的所有商品项信息
            List<ShopCartItemDTO> shopAllShopCartItems = new ArrayList<>();
            for (ShopCartItemDiscountDTO shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemDTO> discountShopCartItems = shopCartItemDiscount.getShopCartItems();
                shopAllShopCartItems.addAll(discountShopCartItems);
            }

            shopCartOrder.setShopCartItemDiscounts(shopCartItemDiscounts);

            applicationContext.publishEvent(new ConfirmOrderEvent(shopCartOrder, req, shopAllShopCartItems));

            actualTotal = NumberUtil.add(actualTotal, shopCartOrder.getActualTotal());
            freightTotal = NumberUtil.add(freightTotal, shopCartOrder.getTransfee());
            total = NumberUtil.add(total, shopCartOrder.getTotal());
            totalCount = totalCount + shopCartOrder.getTotalCount();
            orderReduce = NumberUtil.add(orderReduce, shopCartOrder.getShopReduce());
            shopCartOrders.add(shopCartOrder);

        }

        shopCartOrderMergerDto.setActualTotal(actualTotal);
        shopCartOrderMergerDto.setFreightTotal(freightTotal);
        shopCartOrderMergerDto.setTotal(total);
        shopCartOrderMergerDto.setTotalCount(totalCount);
        shopCartOrderMergerDto.setShopCartOrders(shopCartOrders);
        shopCartOrderMergerDto.setOrderReduce(orderReduce);

        shopCartOrderMergerDto = orderService.putConfirmOrderCache(userId, shopCartOrderMergerDto);

        return R.ok(shopCartOrderMergerDto);
    }

    /**
     * 提交订单-返回订单id集合（购物车/立即购买  提交订单,根据店铺拆单）
     */
    @ApiOperationSupport(order = 20)
    @PostMapping("/submit")
    @Operation(summary = "提交订单-返回订单id集合", description = "根据传入的参数判断是否为购物车提交订单，同时对购物车进行删除，用户开始进行支付；多个店铺拆单，返回订单id集合")
    public R<List<String>> submitOrders(@Valid @RequestBody SubmitOrderREQ submitOrderParam) {
        Long userId = SecurityUtils.getUser().getId();
        ShopCartOrderMergerVO mergerOrder = orderService.getConfirmOrderCache(userId);
        if (mergerOrder == null) {
            throw new BizException(Hint.APP_ORDER_EXPIRED_PLEASE_RETRY);
        }

        List<SubmitOrderREQ.OrderShopParam> orderShopParams = submitOrderParam.getOrderShopParam();

        List<ShopCartOrderDTO> shopCartOrders = mergerOrder.getShopCartOrders();
        // 设置备注
        if (CollectionUtil.isNotEmpty(orderShopParams)) {
            for (ShopCartOrderDTO shopCartOrder : shopCartOrders) {
                for (SubmitOrderREQ.OrderShopParam orderShopParam : orderShopParams) {
                    if (Objects.equals(shopCartOrder.getShopId(), orderShopParam.getShopId())) {
                        shopCartOrder.setRemarks(orderShopParam.getRemark());
                    }
                }
            }
        }

        List<Order> orders = orderService.submit(userId, mergerOrder);

        boolean isShopCartOrder = false;
        // 移除缓存
        for (ShopCartOrderDTO shopCartOrder : shopCartOrders) {
            for (ShopCartItemDiscountDTO shopCartItemDiscount : shopCartOrder.getShopCartItemDiscounts()) {
                for (ShopCartItemDTO shopCartItem : shopCartItemDiscount.getShopCartItems()) {
                    Long cartId = shopCartItem.getCartId();
                    if (cartId != null && cartId != 0) {
                        isShopCartOrder = true;
                    }
                    skuService.removeSkuCacheBySkuId(shopCartItem.getSkuId(), shopCartItem.getProdId());
                    productService.removeProductCacheByProdId(shopCartItem.getProdId());
                }
            }
        }
        // 购物车提交订单时(即有购物车ID时)
        if (isShopCartOrder) {
            cartService.removeShopCartItemsCacheByUserId(userId);
        }
        orderService.removeConfirmOrderCache(userId);
        // 发送消息
        orders.stream().forEach(
        	o -> messageService.sendMsg(
        			NotifyTemplateEnum.order_unpaid.getId(),
        			0L,
        			userId,
        			BizCst.Message.Type.order,
        			BizCst.Message.BindType.order,
        			o.getId())
    	);
        return R.ok(orders.stream().map(o -> o.getId().toString()).toList());
    }

    /**
     * 取消订单
     */
    @ApiOperationSupport(order = 21)
    @PutMapping("/cancel/{orderId}")
    @Operation(summary = "取消订单", description = "根据订单号取消订单")
    @Parameter(name = "orderId", description = "订单id", required = true)
    public R<String> cancel(@PathVariable Long orderId) {
        Long userId = SecurityUtils.getUser().getId();
        Order order = orderService.getById(orderId);
        if (!Objects.equals(order.getUid(), userId)) {
            throw new BizException(Hint.APP_YOU_HAVE_NO_PERMISSION_TO_GET_THE_ORDER_INFORMATION);
        }
        if (!Objects.equals(order.getState(), BizCst.Order.State.unpay)) {
            throw new BizException(Hint.APP_ORDER_PAID);
        }
        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderId);
        order.setOrderItems(orderItems);
        // 取消订单
        orderService.cancelOrders(Collections.singletonList(order));

        // 清除缓存
        for (OrderItem orderItem : orderItems) {
            productService.removeProductCacheByProdId(orderItem.getProdId());
            skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId());
        }
        return R.ok();
    }

    /**
     * 确认收货
     */
    @ApiOperationSupport(order = 22)
    @PutMapping("/receipt/{orderId}")
    @Operation(summary = "确认收货", description = "根据订单号确认收货")
    @Parameter(name = "orderId", description = "订单id", required = true)
    public R<String> receipt(@PathVariable Long orderId) {
        Long userId = SecurityUtils.getUser().getId();
        Order order = orderService.getById(orderId);
        if (!Objects.equals(order.getUid(), userId)) {
            throw new BizException(Hint.APP_YOU_HAVE_NO_PERMISSION_TO_GET_THE_ORDER_INFORMATION);
        }
        if (!Objects.equals(order.getState(), BizCst.Order.State.consignment)) {
            throw new BizException(Hint.APP_THE_ORDER_HAS_NOT_BEEN_DELIVERED_YET);
        }
        List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderId(orderId);
        order.setOrderItems(orderItems);
        // 确认收货
        orderService.confirmReceiptOrder(Collections.singletonList(order));

        for (OrderItem orderItem : orderItems) {
            productService.removeProductCacheByProdId(orderItem.getProdId());
            skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId());
        }
		// 发送消息
        messageService.sendMsg(
    			NotifyTemplateEnum.order_delivered.getId(),
    			0L,
    			userId,
    			BizCst.Message.Type.order,
    			BizCst.Message.BindType.order,
    			order.getId()
    	);
        return R.ok();
    }


    /**
     * 通过id查询订单
     * @param orderId 订单id
     * @return R
     */
	@ApiOperationSupport(order = 50)
    @Operation(summary = "订单详情", description = "订单详情")
    @Parameter(name = "orderId", description = "订单id", required = true)
    @GetMapping("/detail/{orderId}")
    public R<OrderVO> getById(@PathVariable Long orderId) {
		MPJLambdaWrapper<Order> wrapper = new MPJLambdaWrapper<Order>()
				.selectAll(Order.class)
				.selectCollection(OrderItem.class, OrderVO::getOrderItemList, i -> i
						.association(OrderRefund.class, OrderItemVO::getOrderRefund)
						.association(Sku.class, OrderItemVO::getProperties, map -> map.
							result(Sku::getProperties)))
				.selectAssociation(OrderAddress.class, OrderVO::getOrderAddress)
				.leftJoin(OrderAddress.class, OrderAddress::getId, Order::getOrderAddressId)
				.leftJoin(OrderItem.class, OrderItem::getOrderId, Order::getId)
				.leftJoin(OrderRefund.class, on -> on
						.eq(OrderRefund::getOrderItemId, OrderItem::getId)
						.ne(OrderRefund::getState, BizCst.OrderRefund.State.cancel))
				.leftJoin(Sku.class, Sku::getId, OrderItem::getSkuId)
				.eq(Order::getId, orderId)
				.eq(Order::getUid, SecurityUtils.getUser().getId());
		OrderVO vo = orderService.selectJoinOne(OrderVO.class, wrapper);
		if(ObjectUtil.isNotNull(vo)) {
			//分钟
			long min = cacheService.getOrderAutoCancelTime();
			LocalDateTime orderAutoCancelTime = LocalDateTime.from(vo.getCreateTime());
			vo.setAutoCancelTime(orderAutoCancelTime.plusMinutes(min));
		}
		for (OrderItemVO itemVO : vo.getOrderItemList()) {
			if(ObjectUtil.isNotNull(itemVO.getFreightAmount())){
				itemVO.setGrandTotal(itemVO.getTotalAmount().add(itemVO.getFreightAmount()));
			}else {
				itemVO.setGrandTotal(itemVO.getTotalAmount());
			}
			if(ObjectUtil.isNotNull(itemVO.getOrderRefund())) {
				vo.setHasRefund(true);
				itemVO.setHasRefund(true);
			}

		}
	    return R.ok(vo);
    }

	/**
	 * 申请退款
	 * @param req
	 * @return
	 */
	@ApiOperationSupport(order = 57)
    @Operation(summary = "申请退款", description = "申请退款")
    @PostMapping("/refund")
    public R refund(@RequestBody OrderRefundREQ req) {
		orderRefundService.refund(req);
        return R.ok();
    }

	/**
	 * 取消退款
	 * @param ids
	 * @return
	 */
	@ApiOperationSupport(order = 60)
    @Operation(summary = "取消退款", description = "取消退款")
    @PutMapping("/refund/cancel")
    public R refund(@RequestBody List<Long> ids) {
		orderRefundService.cancel(ids);
        return R.ok();
    }


    /**
     * 订单产品添加到购物车
     * @param orderId
     * @return
     */
    @ApiOperationSupport(order = 61)
    @Operation(summary = "订单产品添加到购物车", description = "订单产品添加到购物车")
    @PostMapping("/cart/{orderId}")
    public R cart(@PathVariable String orderId) {
        List<Order> orderList = orderService.getOrderAndItemsList(Arrays.asList(Long.valueOf(orderId)));
        if (CollUtil.isEmpty(orderList)) {
            throw new BizException(Hint.APP_ORDER_NOT_EXIST);
        }
        Long userId = SecurityUtils.getUser().getId();

        List<ShopCartItemDTO> shopCartItems = cartService.getShopCartItems(userId);
        for (OrderItem orderItem : orderList.get(0).getOrderItems()) {
            // 构建购物车请求参数
            ChangeCartREQ req = new ChangeCartREQ();
            req.setProdId(orderItem.getProdId());
            req.setSkuId(orderItem.getSkuId());
            req.setShopId(orderItem.getShopId());
            req.setNum(orderItem.getNum());

            Prod prod = prodService.getProduct(req.getProdId());
            Sku sku = skuService.getSku(req.getSkuId());

            // 当产品状态不正常时，不能添加到购物车
            if (BooleanUtil.isFalse(prod.getIsSale()) || BooleanUtil.isFalse(sku.getIsSale()) || BooleanUtil.isTrue(sku.getIsDeleted())) {
                throw new BizException(Hint.APP_PROD_NOT_SALE, prod.getName());
            }
            for (ShopCartItemDTO shopCartItemDTO : shopCartItems) {
                if (Objects.equals(req.getSkuId(), shopCartItemDTO.getSkuId())) {
                    Cart cart = new Cart();
                    cart.setUid(userId);
                    cart.setNum(req.getNum() + shopCartItemDTO.getProdNum());
                    cart.setId(shopCartItemDTO.getCartId());

                    // 防止购物车变成负数
                    if (cart.getNum() <= 0) {
                        cartService.removeShopCartItemsByCartIds(userId, Collections.singletonList(cart.getId()));
                        return R.ok();
                    }

                    // 当sku实际库存不足时，不能添加到购物车
                    if (sku.getActualStocks() < cart.getNum() && shopCartItemDTO.getProdNum() > 0) {
                        throw new BizException(Hint.APP_PROD_STOCKS_NOT_ENOUGH, sku.getProdName());
                    }
                    cartService.updateShopCartItem(cart);
                    return R.ok();
                }
            }

            // 防止购物车已被删除的情况下,添加了负数的产品
            if (req.getNum() < 0) {
                throw new BizException(Hint.APP_CART_PROD_HAS_BENN_REMOVED);
            }
            // 当sku实际库存不足时，不能添加到购物车
            if (sku.getActualStocks() < req.getNum()) {
                throw new BizException(Hint.APP_PROD_STOCKS_NOT_ENOUGH, sku.getProdName());
            }
            // 前端没有传入shopId时，使用产品的shopId
            if (Objects.isNull(req.getShopId())) {
                req.setShopId(prod.getShopId());
            }

            // 所有都正常时
            cartService.addShopCartItem(req, userId);
        }

        return R.ok();
    }

}
